﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;

/* C# Garbage Collection is run and managed by CLR
 * It runs in a back end thread. Partial Garbage collections run with low thread priority
 * Full Grabage Collection is run with high thread priority.
 * Program execution is temporarily suspended when GC is running
 * CLR allocates memory in the Heap via a contiguous process (a new object is added next / top to the address of old one)
 * unlike a C++ compiler where memory allocation happens via linkedlist. This is faster but it has a drawback that
 * it has no way to know when it will run out of space. So the CLR needs to constantly clean the heap removing dead objects.
 * Garbage Collection Process
 * 1. CLR traverses through the "roots" of each object on the heap via "GC Root" to check if an object has a live reference.
 * 1.1 The algorithm that it uses is mark and sweep algorithm. It marks all objects which do not have live reference and sweeps them.
 * 2. The new objects (that are being looked) at are Gen 0
 * 3. If the references are dead, then the heap is cleared of that object to reclaim that part.
 * 4. Objects that have survived Gen 0 are marked as Gen 1. (Objects that survive Gen 1 are marked as Gen 2)
 * 5. CLR then reshuffles the heap moving Gen 2 at the lower end of the heap, followed by Gen 1 and Gen 0 and then free space
 * 6. This enables the CLR to quickly assign a memory to a new object being created on the heap.
 * 7. Also, due to this process, the CLR knows that Gen 0 objects are most likely to be dead, followed by Gen 1 and Gen 2
 * 8. The older the object, the least likely it is to get destroyed.
 * 9. If the GC finds that an object is marked Finalize, it doesn't touch it.
 * 10. The finalize method is run after GC completes its cycle (partial or full) and hence its an overhead.
 * 11. The finalize is now implemented using the ~ (Destructor)
 * 12. Implement IDisposable and suppress finalize
 * 
 */

namespace Demo.Framework.GC
{
    public class DesctructorClass
    {
        Stopwatch sw;
        private string _identifier;

        public DesctructorClass(string identifier)
        {
            _identifier = identifier;
            sw = new Stopwatch();
            sw.Start();
        }

        public override string ToString()
        {
            return _identifier;
        }
                
        ~DesctructorClass()
        {
            sw.Stop();
            Console.WriteLine("DestructorClass - {0} - is getting Destroyed (Finalized). Lifespan: {1}",
                _identifier, sw.Elapsed.Milliseconds);
        }
    }

    public class DisposableClass : IDisposable
    {
        Stopwatch sw;
        private string _identifier;

        public DisposableClass(string identifier)
        {
            _identifier = identifier;
            sw = new Stopwatch();
            sw.Start();
        }
        
        public void Dispose()
        {
            System.GC.SuppressFinalize(this);
            if (sw != null)
            {
                sw.Stop();
                Console.WriteLine("DisposableClass - {0} - is getting Destroyed (Disposed). Lifespan: {1}",
               _identifier, sw.Elapsed.Milliseconds);
            }
            else
            {
                Console.WriteLine("DisposableClass - {0} - is getting Destroyed (Disposed)", _identifier);
            }
           
            Dispose(true);
        }

        public void Dispose(bool disposing)
        {
            if (disposing)
            {
                // dispose managed object
                try
                {
                    sw = null;
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex.Message);
                }               
               
            }
            // dispose unmanaged object
            Console.WriteLine("DisposableClass - {0} - is Destroyed (Disposed)", _identifier);
        }

        ~DisposableClass()
        {
            sw.Stop();
            Console.WriteLine("DisposableClass - {0} - is getting Destroyed (Finalized). Lifespan: {1}",
                _identifier, sw.Elapsed.Milliseconds);
            Dispose(false);
        }
    }

}
